package com.framework.es.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author zhaoj
 * @create 2021/12/27
 */
public class ElasticsearchService {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * 根据实体对象生成Mapping
     * @param clazz
     */
    public void createIndex(Class clazz) {
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(clazz);
        if(!indexOperations.exists()) {
            indexOperations.create();
            indexOperations.putMapping(indexOperations.createMapping());
        }
    }

    /**
     * 删除索引
     * @param clazz
     */
    public void delIndex(Class clazz){
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(clazz);
        if(!indexOperations.exists()) {
            indexOperations.delete();
        }
    }

    /**
     * 删除对象
     * @param clazz
     */
    public String delDoc(String id, Class clazz){
        return elasticsearchRestTemplate.delete(id,clazz);
    }

    /**
     * 保存对象
     * @param obj
     */
    public boolean saveDoc(Object obj) {
        return ObjectUtil.isNotNull(elasticsearchRestTemplate.save(obj));
    }

    /**
     * 部分更新
     * @return
     */
    public void updateBatch(List<UpdateQuery> updateQuery, Class clazz){
        elasticsearchRestTemplate.bulkUpdate(updateQuery, elasticsearchRestTemplate.getIndexCoordinatesFor(clazz));
    }

    /**
     * 高亮分页搜索
     * @return
     */
    public  <T> SearchHits<T> hitSearch(int current, int pageSize, String keyword, Map<String, Object> params, Map<String, Boolean> orders, List<String> fileds, Class<T> clazz){
        //需要查询的字段
        List<HighlightBuilder.Field> fieldHigh = new ArrayList<>();
        BoolQueryBuilder boolQueryBuilder= QueryBuilders.boolQuery();
        if(CollectionUtil.isNotEmpty(params)) {
            for (Map.Entry<String, Object> p : params.entrySet()) {
                if(p.getValue() instanceof  List) {
                    List<String> values = (List<String>) p.getValue();
                    boolQueryBuilder.must().add(QueryBuilders.termsQuery(p.getKey(),values));
                } else {
                    boolQueryBuilder.must().add(QueryBuilders.termQuery(p.getKey(), p.getValue()));
                }
            }
        }

        if(StrUtil.isNotEmpty(keyword)) {
            BoolQueryBuilder childBoolQueryBuilder = QueryBuilders.boolQuery();
            for (String filed : fileds) {
                childBoolQueryBuilder.should().add(QueryBuilders.matchQuery(filed, keyword));//高亮字段
                fieldHigh.add(new HighlightBuilder.Field(filed));
            }
            boolQueryBuilder.must().add(childBoolQueryBuilder);
        }

        List<SortBuilder> sorts = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(orders)) {
            for (Map.Entry<String, Boolean> order : orders.entrySet()) {
                sorts.add(SortBuilders.fieldSort(order.getKey()).order(order.getValue() ? SortOrder.ASC : SortOrder.DESC));
            }
        }

        //构建高亮查询
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .withHighlightFields(ArrayUtil.toArray(fieldHigh, HighlightBuilder.Field.class))
                .withHighlightBuilder(new HighlightBuilder().preTags("<em>").postTags("</em>"))
                .withPageable(PageRequest.of(current, pageSize));

        //设置多个排序
        sorts.forEach(item -> {
            nativeSearchQueryBuilder.withSort(item);
        });

        NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();
        return elasticsearchRestTemplate.search(searchQuery, clazz);
    }
}
